﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Shapes;
using System.Windows.Controls;
using System.Windows.Media;
using Gencode.VECore.History;
using Gencode.VECore.VectorShape;
using Gencode.VECore.Tools;
//using System.Runtime.Serialization;

namespace Gencode.VECore
{
    /// <summary>
    /// Types of shapes that can be contained in the drawing canvas
    /// </summary>
	public enum ToolType { Line, SelectionTool, Rectangle, Ellipse, Polygon, Curve, None };

    /// <summary>
    /// Delegate that will be executed when a layer is added
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    public delegate void LayerAddedEventHandler(object sender, LayerAddedEventArgs e);

    /// <summary>
    /// Drawingcanvas control.
    /// This canvas can be added to the WPF form for drawing on.
    /// By default contains 1 layer for drawing shapes on.
    /// Layers with shapes can be added dynamically.
    /// </summary>
    public class CanvasDocument : Canvas
    {
        /// <summary>
        /// Event gets executed when a layer is added
        /// </summary>
        public event LayerAddedEventHandler LayerAdded;

        /// <summary>
        /// Creates a new canvas for drawing on.
        /// By default contais 1 layer
        /// </summary>
        public CanvasDocument()
        {
            InitializeComponent();

            AddLayer();

            //TODO:
            //Layers??
            _historyManager = new HistoryManager(SelectedLayer.ShapeList);

            //TODO:
            //Layers in initialize??
            //Initialize();

            //set this instance to the private static so that static vars can use it
            InitializedCanvasManager = this;
        }

        /// <summary>
        /// deletes all layers and the shapes contained in the layer
        /// has to be executed everytime when the canvas will be destroyed
        /// </summary>
        public void Dispose()
        {
            foreach (CanvasLayer layer in _canvasLayers)
            {
                layer.Dispose();
            }

            _canvasLayers.Clear();
            SelectedLayer = null;

            ClearHistory();
        }

        private void InitializeComponent()
        {
            this.Background = System.Windows.Media.Brushes.White;

            this.SizeChanged += Canvas_SizeChanged;
            this.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(drawingCanvas_MouseLeftButtonDown);
            this.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(drawingCanvas_MouseLeftButtonUp);
            this.MouseRightButtonUp += new System.Windows.Input.MouseButtonEventHandler(drawingCanvas_MouseRightButtonUp);
            this.MouseMove += new System.Windows.Input.MouseEventHandler(drawingCanvas_MouseMove);
        }

        #region Events

        protected override void OnRender(System.Windows.Media.DrawingContext dc)
        {
            base.OnRender(dc);

            if (ShowGrid)
            {
                Pen p = new Pen(Brushes.Beige, 1);

                int h = (int)(this.Height / 10);
                int w = (int)(this.Width / 10);

                for (int i = 0; i < h; i++)
                    dc.DrawLine(p, new Point(0, i * 10), new Point(Width, i * 10));
                for (int i = 0; i < w; i++)
                    dc.DrawLine(p, new Point(i * 10, 0), new Point(i * 10, Height));
            }
        }

        private void Canvas_SizeChanged(object sender, System.Windows.SizeChangedEventArgs e)
        {
            if(Layers!= null)
                foreach (CanvasLayer layer in Layers)
                {
                    layer.Width = this.Width;
                    layer.Height = this.Height;
                }
        }

        private void drawingCanvas_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (SelectedLayer != null && CurrentTool != null)
                CurrentTool.OnMouseLeftButtonDown(this, e);
        }

        private void drawingCanvas_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (SelectedLayer != null && CurrentTool != null)
                CurrentTool.OnMouseLeftButtonUp(this, e);
        }

        private void drawingCanvas_MouseRightButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (SelectedLayer != null && CurrentTool != null)
                CurrentTool.OnMouseRightButtonUp(this, e);
        }

        private void drawingCanvas_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (SelectedLayer != null && CurrentTool != null)
                CurrentTool.OnMouseMove(this, e);
        }

        #endregion

        #region Layers

        CanvasLayer _selectedCanvas;
        /// <summary>
        /// CanvasLayer that is selected for drawing on
        /// </summary>
        public CanvasLayer SelectedLayer
        {
            get
            {
                //if (_selectedCanvas == null)
                //    throw new Exception("CADCanvasobjekt was not initialized");
                return _selectedCanvas;
            }
            set
            {
                if (_canvasLayers.Contains(value) || value == null)
                    _selectedCanvas = value;
                else
                    throw new Exception("Layer is not contained in layer collection.\nPlease add lyer first!");
            }
        }

        List<CanvasLayer> _canvasLayers;
        /// <summary>
        /// List of layers in this canvas
        /// </summary>
        public List<CanvasLayer> Layers
        {
            get
            {
                return _canvasLayers;
            }
            private set
            {
                _canvasLayers = value;
                if (_canvasLayers.Count > 0)
                    SelectedLayer = _canvasLayers[0];
            }
        }

        /// <summary>
        /// adds a empty layer to the canvas
        /// </summary>
        public void AddLayer()
        {
            AddLayer(new CanvasLayer());
        }

        /// <summary>
        /// adds a layer to the canvas
        /// </summary>
        /// <param name="layer">layer to be added</param>
        public void AddLayer(CanvasLayer layer)
        {
            if (_canvasLayers == null)
                _canvasLayers = new List<CanvasLayer>();

            _canvasLayers.Insert(0, layer);

            this.Children.Insert(0, layer);

            layer.Height = this.Height;
            layer.Width = this.Width;

            if (_curentTool != null)
                layer.CurentTool = _curentTool;

            if (SelectedLayer != null)
                SelectedLayer.Selecteable = false;

            SelectedLayer = layer;

            if (LayerAdded != null)
                LayerAdded(this, new LayerAddedEventArgs(layer));
        }

        /// <summary>
        /// removes the layer that is currently selected
        /// </summary>
        public void RemoveLayer()
        {
            if (SelectedLayer != null)
                _canvasLayers.Remove(SelectedLayer);

            if (_canvasLayers.Count > 0)
                SelectedLayer = _canvasLayers[0];
            else
                SelectedLayer = null;
        }

        public void ClearLayers()
        {
            Layers.Clear();
        }

        /// <summary>
        /// Forces all layers to refresh
        /// </summary>
        public void Refresh()
        {
            foreach (CanvasLayer layer in Layers)
                layer.Refresh();
        }

        #endregion

        #region History

        HistoryManager _historyManager;

        /// <summary>
        /// Add command to history.
        /// </summary>
        public void AddCommandToHistory(Command command)
        {
            //TODO:
            //Layers??
            _historyManager.AddCommandToHistory(command);
        }

        /// <summary>
        /// Clear command history.
        /// </summary>
        public void ClearHistory()
        {
            //TODO:
            //Layers??
            _historyManager.ClearHistory();
        }

        /// <summary>
        /// Undo
        /// </summary>
        public void Undo()
        {
            //TODO:
            //Layers??
            _historyManager.Undo();
            SelectedLayer.Refresh();
        }

        /// <summary>
        /// Redo
        /// </summary>
        public void Redo()
        {
            //TODO:
            //Layers??
            _historyManager.Redo();
            SelectedLayer.Refresh();
        }

        #endregion

        #region Shapes

        /// <summary>
        /// Adds a VECShape to the canvas/layer and registers it in the shapelist of the layer
        /// </summary>
        /// <param name="shapeObject"></param>
        public void AddShape(VECShape shape)
        {
            SelectedLayer.AddShape(shape);
            //this.InvalidateVisual();
        }

        public void RemoveShape(VECShape shape)
        {
            SelectedLayer.RemoveShape(shape);
        }

        public void RemoveSelection()
        {
            var changeCmd = new StateChangeCommand(SelectedLayer.ShapeList);

            SelectedLayer.RemoveSelection();

            // Keep state after removing shapes and add command to history
            changeCmd.NewState(SelectedLayer.ShapeList);
            AddCommandToHistory(changeCmd);
        }

        /// <summary>
        /// Selects all objects in the curent layer that intersect with the rectangle
        /// </summary>
        /// <param name="rectangle"></param>
        public void SelectShapes(Rect rectangle)
        {
            SelectedLayer.ShapeList.SelectShapes(rectangle);
        }

        /// <summary>
        /// Adds a VECShape to the base canvas without registration in a shapelist of a layer
        /// Reference should not be lost...
        /// </summary>
        /// <param name="shape"></param>
        public void AddUnregisteredShape(VECShape shape)
        {
            if (InitializedCanvasManager != null)
            {
                InitializedCanvasManager.Children.Add(shape);
            }
        }

        /// <summary>
        /// Removes an unregistered Shape from the base canvas
        /// </summary>
        /// <param name="shape"></param>
        public void RemoveUnregisteredShape(Shape shape)
        {
            if (InitializedCanvasManager != null &&
                InitializedCanvasManager.Children.Contains(shape))
            {
                InitializedCanvasManager.Children.Remove(shape);
            }
        }

        #endregion

        #region Global scope (Tools, Options)

        static CanvasDocument InitializedCanvasManager;

        #region Options

        static bool _showGrid;
        public static bool ShowGrid
        {
            get
            {
                return _showGrid;
            }
            set
            {
                _showGrid = value;
                if (InitializedCanvasManager != null)
                    InitializedCanvasManager.InvalidateVisual();
            }
        }

        #endregion

        #region Tools

        static Dictionary<string, VectorTool> _tools;

        static VectorTool _curentTool;
        public static VectorTool CurrentTool
        {
            get
            {
                return _curentTool;
            }
            set
            {
                _curentTool = value;
            }
        }

        public static void AddTool(string key, VectorTool tool)
        {
            if (_tools == null)
                _tools = new Dictionary<string, VectorTool>();

            if (!_tools.ContainsKey(key))
                _tools.Add(key, tool);

            if (_tools.Count == 1)
            {
                _curentTool = tool;
            }
        }

        public static void SelectTool(string key)
        {
            if (_tools.ContainsKey(key))
            {
                _curentTool = _tools[key];
            }
            else
                throw new Exception("Tool " + key + " is not contained in tools container!");
        }

        static ToolType _toolType = ToolType.None;
        /// <summary>
        /// 
        /// </summary>
        public static ToolType SelectedToolType
        {
            get
            {
                return _toolType;
            }
            set
            {
                _toolType = value;

                switch (_toolType)
                {
                    case ToolType.Line:
                        SelectTool("line");
                        break;
                    case ToolType.SelectionTool:
                        SelectTool("grab");
                        break;
                    case ToolType.Rectangle:
                        SelectTool("rectangle");
                        break;
                    case ToolType.Ellipse:
                        SelectTool("ellipse");
                        break;
                    case ToolType.Polygon:
                        SelectTool("path");
                        break;
                    case ToolType.Curve:
                        SelectTool("curve");
                        break;
                }
            }
        }

        #endregion

        #endregion






        ///// <summary>
        ///// Draw all graphics objects to DrawingContext supplied by client.
        ///// Can be used for printing or saving image together with graphics
        ///// as single bitmap.
        ///// 
        ///// withSelection = true - draw selected objects with tracker.
        ///// </summary>
        //public void Draw(DrawingContext drawingContext, bool withSelection)
        //{
        //    bool oldSelection = false;

        //    foreach (VECShape b in SelectedLayer.ShapeList)
        //    {
        //        if (!withSelection)
        //        {
        //            // Keep selection state and unselect
        //            oldSelection = b.Selected;
        //            b.Selected = false;
        //        }

        //        b.Draw(drawingContext);

        //        if (!withSelection)
        //        {
        //            // Restore selection state
        //            b.Selected = oldSelection;
        //        }
        //    }
        //}





    }

    public class LayerAddedEventArgs : EventArgs
    {
        CanvasLayer _layer;

        public LayerAddedEventArgs(CanvasLayer layer)
        {
            _layer = layer;
        }

        public CanvasLayer Layer
        {
            get
            {
                return _layer;
            }
        }
    }
}
